package com.hitqz.robot.biz.listener;

import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.util.concurrent.RateLimiter;
import com.hitqz.robot.api.business.enums.EquipmentEnum;
import com.hitqz.robot.api.business.event.RobotMapPosUpdateEvent;
import com.hitqz.robot.api.business.event.TrackPowerEvent;
import com.hitqz.robot.api.business.event.TrackUltrasonicTriggerEvent;
import com.hitqz.robot.api.common.dto.robot.RobotGoTargetPosDto;
import com.hitqz.robot.api.common.dto.tickets.CtrlTicketsEvent;
import com.hitqz.robot.api.common.dto.warning.AddWarningDto;
import com.hitqz.robot.api.common.entity.Robot;
import com.hitqz.robot.api.common.entity.RobotEquipment;
import com.hitqz.robot.api.common.entity.RobotMap;
import com.hitqz.robot.api.common.entity.RobotMapPos;
import com.hitqz.robot.biz.core.FileProperties;
import com.hitqz.robot.biz.flow.util.LiteFlowUtil;
import com.hitqz.robot.biz.service.RobotEquipmentService;
import com.hitqz.robot.biz.service.RobotMapPosService;
import com.hitqz.robot.biz.service.RobotMapService;
import com.hitqz.robot.biz.service.RobotService;
import com.hitqz.robot.camera.EquipmentFactory;
import com.hitqz.robot.camera.IEquipmentService;
import com.hitqz.robot.camera.configure.EquipmentCmdEnum;
import com.hitqz.robot.camera.dto.*;
import com.hitqz.robot.driver.parent.RobotDriverService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.io.File;
import java.util.List;
import java.util.Optional;

@Component
@Slf4j
@AllArgsConstructor
public class TrackEventListener {

    private final RateLimiter ultrasonicTriggerEventLimiter = RateLimiter.create(1);

    private final RobotEquipmentService robotEquipmentService;

    private final RobotMapPosService robotMapPosService;

    private final EquipmentFactory equipmentFactory;

    private final FileProperties fileProperties;

    private final static RateLimiter autoChargeLimiter = RateLimiter.create(1);

    private final RobotService robotService;

    private final RobotDriverService robotDriverService;

    private final RobotMapService robotMapService;

    @Async("robotEventExecutor")
    @EventListener
    public void onRobotMapPosUpdateEvent(RobotMapPosUpdateEvent event) {
        String mapCode = event.getMapCode();
        log.info("mapCode {} update mapPost", mapCode);
        List<RobotMapPos> list = robotMapPosService.list(Wrappers.<RobotMapPos>lambdaQuery().eq(RobotMapPos::getMapCode, mapCode));
        RobotMap map = robotMapService.findByMapCode(mapCode);
        map.setPosList(list);
        robotDriverService.selMap(map);
    }

    @Async("robotEventExecutor")
    @EventListener
    public void onUltrasonicTriggerEvent(TrackUltrasonicTriggerEvent event) {
        try {
            boolean triggerFlag = false;
            if (event.getBackUltrasonicTriggerStatus() == 1 || event.getFrontUltrasonicTriggerStatus() == 1) {
                triggerFlag = true;
            }
            if (triggerFlag && !ultrasonicTriggerEventLimiter.tryAcquire(10)) {
                log.info("[track]ultrasonic trigger event too frequent, ignore");
                return;
            }
            RobotEquipment ptz = robotEquipmentService.getOne(Wrappers.<RobotEquipment>lambdaQuery().eq(RobotEquipment::getType, EquipmentEnum.PTZ.getType()).last("limit 1"));
            String content = "";
            if (ptz != null) {
                List<EquipmentParamsDto> cameraParamDTO = null;
                if (event.getBackUltrasonicTriggerStatus() == 1) {
                    // 后超声波触发
                    cameraParamDTO = CameraParamDTO.getBack(ptz.getIp(), ptz.getChannel());
                    content = "后退方向有障碍物";
                } else if (event.getFrontUltrasonicTriggerStatus() == 1) {
                    // 前超声波触发
                    cameraParamDTO = CameraParamDTO.getOriginal(ptz.getIp(), ptz.getChannel());
                    content = "前进方向有障碍物";
                } else {
                    //都没有触发
                    cameraParamDTO = CameraParamDTO.getOriginal(ptz.getIp(), ptz.getChannel());
                }
                IEquipmentService ptzService = equipmentFactory.getServiceByBrand(ptz.getBrand());
                QueryParamsDto queryParamsDto = new QueryParamsDto();
                queryParamsDto.setChannel(ptz.getChannel());
                queryParamsDto.setPassword(ptz.getPassword());
                queryParamsDto.setIp(ptz.getIp());
                queryParamsDto.setPort(ptz.getPort());
                queryParamsDto.setUsername(ptz.getUsername());
                ptzService.setEquipmentParams(queryParamsDto, cameraParamDTO, true);
                // 到达判断，已经交给setEquipmentParams true 字段
                //if (triggerFlag) {
                //    QueryCameraParamDTO queryCameraParamDTO = new QueryCameraParamDTO();
                //    queryCameraParamDTO.setIp(ptz.getIp());
                //    queryCameraParamDTO.setChannel(ptz.getChannel());
                //    for (int i = 0; i < 8; i++) {
                //        Thread.sleep(1000);
                //        CameraParamDTO cameraParam = ptzService.getCameraParam(queryCameraParamDTO);
                //        if ((Math.abs(cameraParam.getAzimuth() - cameraParamDTO.getAzimuth()) < 10
                //                && Math.abs(cameraParam.getElevation() - cameraParamDTO.getElevation()) < 10)
                //                || Math.abs(cameraParam.getElevation() - cameraParamDTO.getElevation()) > 3590) {
                //            log.info("[track]ptz go reach target position");
                //            break;
                //        }
                //    }
                //}
            }
            RobotEquipment camera = robotEquipmentService.getOne(Wrappers.<RobotEquipment>lambdaQuery().eq(RobotEquipment::getType, EquipmentEnum.VISIBLE_LIGHT_CHANNEL.getType()).last("limit 1"));
            String path = "";
            if (triggerFlag && camera != null) {
                QueryParamsDto queryParamsDto = new QueryParamsDto();
                queryParamsDto.setChannel(camera.getChannel());
                queryParamsDto.setPassword(camera.getPassword());
                queryParamsDto.setIp(camera.getIp());
                queryParamsDto.setPort(camera.getPort());
                queryParamsDto.setUsername(camera.getUsername());
                IEquipmentService cameraService = equipmentFactory.getServiceByBrand(camera.getBrand());
                cameraService.setEquipmentParams(queryParamsDto, CameraParamDTO.getOriginal(camera.getIp(), camera.getChannel()), true);
                String folder = "warning" + File.separator + DateUtil.format(new DateTime(), "yyyy-MM-dd");
                TakePicParamsDto paramsDto = new TakePicParamsDto();
                paramsDto.setBasePath(fileProperties.getLocal().getBasePath());
                paramsDto.setFolder(folder);
                MediaFileDto takePic = (MediaFileDto) cameraService.executeCmd(queryParamsDto, true, EquipmentCmdEnum.TAKE_PIC,paramsDto);
                path = takePic.getRelativePath();
            }
            if (triggerFlag) {
                AddWarningDto addWarningDto = new AddWarningDto();
                addWarningDto.setTitle("避障触发");
                addWarningDto.setContent(content);
                addWarningDto.setCode("");
                addWarningDto.setSuggestion("请查看障碍物");
                addWarningDto.setLevel(0);
                addWarningDto.setPaths(path);
                SpringUtil.getApplicationContext().publishEvent(addWarningDto);
            }
        }catch (Exception e){

        }
    }


    @Async("robotEventExecutor")
    @EventListener
    public void onPowerEvent(TrackPowerEvent trackPowerEvent){
        Robot robot = robotService.getDefaultRobot();
        Integer chargeThreshold = Optional.ofNullable(robot).map(Robot::getChargeThreshold).orElse(0);
        if (trackPowerEvent.getPercentage() <= chargeThreshold && trackPowerEvent.getCurrentDirection() == 0) {
            if (!autoChargeLimiter.tryAcquire(60 * 5)) {
                return;
            }
            log.info("[track]power:{}<chargeThreshold:{} and now is no charge,go charge", trackPowerEvent.getPercentage(), chargeThreshold);
            //停止任务
            CtrlTicketsEvent ctrlTicketsEvent = new CtrlTicketsEvent();
            ctrlTicketsEvent.setType(CtrlTicketsEvent.TYPE_STOP);
            ctrlTicketsEvent.setMessage("返航充电,任务停止");
            ctrlTicketsEvent.setTicketsId(LiteFlowUtil.ticketsId);
            SpringUtil.getApplicationContext().publishEvent(ctrlTicketsEvent);
            //返航充电
            RobotDriverService service = SpringUtil.getBean("robotDriverService");
            service.robotTaskGoTarget(RobotGoTargetPosDto.builder().code("0").build());
        }
    }


}
